require 'active_unreal/unrealdb'
require 'active_unreal/validations'

module ActiveUnreal
  class Base
    attr_accessor :document_id, :saved ,:new_record
 
    @@attributes = {}
    @@default_doc_id = nil
   
    def initialize(attributes = {})
      @document_id = ""
      @new_record = true
      @@attributes.each_key do |key|
        self.instance_eval "def #{key}; @#{key}; end"
        self.instance_eval "def #{key}=(value); @#{key} = value; end"
        eval "@#{key} = @@attributes['#{key}']"
        # Colocar aqui o metodo que pegar os atributos iguias ao tipo data que vem data(i1) data(i2) para fazer o parse
        eval "@#{key} = attributes['#{key}'] if attributes['#{key}']"
      end
      @saved = false
      yield self if block_given?
      
      if @@default_doc_id
        eval "@document_id = @#{@@default_doc_id}"
      else
        eval "@document_id = @#{@@attributes.first.first}"
      end
    end
    
    def new_record?
      @new_record || false
    end

    def id
      @document_id
    end

    def id=(value)
      @document_id = value
    end
    
    def to_param
      @saved ? @document_id : nil
    end
   
    def save
      cur = @@connection.get_cursor
      eval "@document_id = @#{@@default_doc_id}" if @@default_doc_id
      doc = to_doc
      return false unless doc
      if !@saved
        @saved = cur.insert_document(doc)
        # inserir no documento geral
        if @saved
          @new_record = false
          doc_geral = cur.get_document("All" + self.class.to_s)
          if doc_geral
            found = false
            doc_geral['ids'].each do |d|
              if d == @document_id
                found = true
                break
              end
            end
            if !found
              doc_geral['ids'] << @document_id
              cur.update_document(doc_geral)
            end
          else
            doc_geral = Document.new("All" + self.class.to_s)
            doc_geral << {'ids' => [@document_id]}
            cur.insert_document(doc_geral)
          end
        end
        return @saved
      else
        return cur.update_document(doc)
      end
    end
    
    def update_attributes(attributes = {})
      attributes.each_pair do |att, value|
        if @@attributes[att]
          eval "@#{att} = '#{value}'"
        end
      end
      save
    end
   
    def destroy
      remove
    end
    
    def remove
      cur = @@connection.get_cursor
      removed = cur.remove_document(self.class.to_s + '-' + @document_id)
      if removed
        @saved = false
        doc_geral = cur.get_document("All" + self.class.to_s)
        doc_geral['ids'].delete_if{|d| d == @document_id}
        cur.update_document(doc_geral)
      end
      return removed
    end
    
    def to_doc
      document = nil
      if @document_id
        document = Document.new(self.class.to_s + '-' + @document_id)
        @@attributes.each_key do |key|
          value = eval "@#{key}"
          document << { key => value}
        end
      end
      document
    end

    def errors
      Errors.new(self)
    end

    class << self 
      
      def has(name, default = "")
        unless name.is_a?(String)
          raise Exception, "The name of attribute is not a String"
        end
        @@attributes[name] = default
      end
      
      def attr_document_id(attr)
        @@default_doc_id = attr || nil
      end
      
      def connection(conn)
        @@connection = conn
        @@connection.connect
      end
      
      def close_connection
        @@connection.close
      end
      
      def find(arg)
        if arg == :all
          cur = @@connection.get_cursor
          str = "All" + to_s
          doc = cur.get_document(str)
          return [] unless doc
          result = []
          doc['ids'].each{|doc_id| result << get(doc_id)}
          return result  
        else
          get(arg)
        end
      end
      
      def all
        self.find(:all)
      end
      
      def primary_key
        :document_id
      end
 
      def get(document_id)
        doc_id = to_s + "-" + document_id
        cur = @@connection.get_cursor
        doc = cur.get_document(doc_id)
        if doc
           n_doc = new_at_document(doc)
	   n_doc.saved = true
           n_doc.new_record = false
           return n_doc
        end
        return new
      end
      
      def new_at_document(document)
        begin

          doc_id = document['document_id'].split(to_s + "-")
          
          if doc_id.length > 1
            doc_id = doc_id[1..-1].join("")
          else
            doc_id = doc_id[0]
          end 
          internal_new(doc_id, document)
        rescue Exception => e
          return nil
        end
      end
      
      def query_to_document(qry)
        cur = @@connection.get_cursor
        qry = qry.split("=>")
        qry[0] = to_s + "-" + qry[0]
        qry = qry.join("=>")
        return cur.query(qry)
      end
      
      private
      def internal_new(doc_id, document)        
        object = new(doc_id) do |o|
          document.to_h.each_pair do |key, value|
            if key != 'document_id'
              eval "o.#{key} = '#{value}'"
            end
          end
        end
        
        return object
      end
      
    end
  end
end
